#ifndef HLATREE_H
#include "HLATree.h"
#define HLATREE_H
#endif  /* HLATREE_H */

#include "sam.h"

// globals
int debug = 0;

HLATree::HLATree() {
    _root.setName("ROOT");
}

void HLATree::buildHLATree(std::string filename) {
    gzFile fp;
    kseq_t *seq;
    int l;

    if (debug) std::cout << "HLA Tree building has been called \n\n";

// Read the reference fasta file with kseq.h
    fp = gzopen ((char*)filename.c_str(), "r");
    seq = kseq_init(fp);

    while ((l = kseq_read(seq)) >= 0) {
        // Parse the sequence name
        std::vector<std::string> nameSplit;
        std::deque<std::string> hla;
        char nameCopy[strlen(seq->name.s)+1];
        strcpy(nameCopy, seq->name.s);
//        nameCopy=seq->name.s;
        int count = 0;

        if (debug) std::cout << "\nPrinting HLA Array for "<< seq->name.s<< " \n";

        for (char *token = std::strtok(nameCopy, "_")
                ;token;token = std::strtok(NULL, "_")) {
            nameSplit.push_back(token);
        }

        count = 0;
        for (char *token = std::strtok((char*)nameSplit[1].c_str(), "[:*]")
                ;token ;token = std::strtok(NULL, ":")) {
            hla.push_back(token);
        }

        // nameSplit print here
        if (debug)  { 
            for (int i = 0; i < 4; i++) {
                std::cout << nameSplit[i] << std::endl;
            }
            for (int i = 0; i < hla.size(); i++) {
                std::cout << hla[i] << std::endl;
            }

        }
        _insertRefNode(&_root, seq, hla);
    }
    kseq_destroy(seq);
    gzclose(fp);
    if (debug) std::cout << "debug, buildHLATree ran successfully\n";
}

void HLATree::_insertRefNode(Node *currentNode, \
        kseq_t* seq, \
        std::deque<std::string> hla) {
    // First check if a child of the current node with the same name exists
    // if not, first create the node
    Node *child;
    if (debug) std::cout<<"debug, _insertRefNode called\n";
    if (hla.size() > 0) {
        std::string nextHLA = hla.front();
        if (debug) std::cout << "hlasize is " << hla.size() << std::endl;
        hla.pop_front();
        if (!currentNode -> childExists(nextHLA)) {
            Node *newChild = new Node(nextHLA);
            currentNode->addChild(newChild);
        }
        child = currentNode->getChild(nextHLA);

        // call _insertRefNode on the child with a shifted HLA array
        if (debug) std::cout << "debug, adding a new node named " << nextHLA << " as a child of " << currentNode->getName() << std::endl;
        _insertRefNode(child, seq, hla);
    }

    // If there are no more ID's in the HLAId array, add the sequence to the current Node
    else {
        if (debug) std::cout<<"debug, should create a sequence node at this point with the name "<< seq->name.s<< " \n";
        currentNode->addSeq(seq->name.s, seq->seq.s);
    }
}

void HLATree::printTree() {
    if (debug) std::cout << "DEBUG printTree called\n";
    _recursivePrint(&_root);
    std::cout << _root.getName() << "\n";
    if (debug) std::cout << "DEBUG printTree finished\n";
}

// Probably should change this to breadthFirstPrint and depthFirstPrint
void HLATree::_recursivePrint(Node* currentNode) {
    std::map<std::string, Node*> children = currentNode->getChildren();
//    std::map< std::string, Node* >::const_iterator last_iter = children.end();
//    --last_iter;

    if (children.size()) std::cout << "(";
    for ( std::map< std::string, Node* >::const_iterator iter = children.begin();
            iter != children.end(); ++iter ) {
        _recursivePrint(iter->second);
        std::cout << iter->first;
//        if (iter != last_iter) std::cout << "," ;
        if (iter != --children.end()) std::cout << "," ;
    }
     if (children.size()) std::cout << ")";
}


void HLATree::printSequences() {
    _recursivePrintSequence(&_root);
}

void HLATree::_recursivePrintSequence(Node* currentNode) {
    std::map<std::string, Node*> children = currentNode->getChildren();
    std::map<std::string, std::string> sequences = currentNode->getSequences();
    for ( std::map< std::string, Node* >::const_iterator iter = children.begin();
            iter != children.end(); ++iter ) {
        _recursivePrintSequence(iter->second);
    }
    
    for ( std::map< std::string, std::string >::const_iterator iter = sequences.begin();
            iter != sequences.end(); ++iter ) {
        std::cout << ">"<<iter->first << "\n" << iter->second << "\n";
    }
}

